package apigateway.project.core.filter.loadbalance;

import apigateway.project.commen.config.ServiceInstance;
import apigateway.project.commen.exception.NotFoundException;
import apigateway.project.core.CacheConfig;
import apigateway.project.core.context.GlobalContext;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

import static apigateway.project.commen.enums.ResponseCode.SERVICE_INSTANCE_NOT_FOUND;

/**
 * 提供一致性Hash算法分配后端服务的负载均衡算法
 */
@Slf4j
public class ConsistentHashLoadBalanceRule implements LoadBalanceGatewayRule{

    @Override
    @Deprecated
    public ServiceInstance choose(String serviceName) {
        return null;
    }

    @Override
    public ServiceInstance choose(GlobalContext ctx) {
        //暂定使用请求路径作为一致性哈希的健
        String path = ctx.getRequest().getPath();

        //获取服务实例集合
        Set<ServiceInstance> serviceInstanceSet = CacheConfig.getCacheConfig().getServiceByServiceName(ctx.getRule().getServiceName());
        if (serviceInstanceSet.isEmpty()) {
            log.warn("No instance available for: {}", ctx.getRule().getServiceName());
            throw new NotFoundException(SERVICE_INSTANCE_NOT_FOUND);
        }

        //添加服务实例集合转换为instandId作为节点存到哈希环
        List<String> serviceinstandIdList = serviceInstanceSet.stream()
                .map(ServiceInstance::getInstanceId)
                .collect(Collectors.toList());
        ConsistentHash consistentHash = new ConsistentHash(serviceinstandIdList);

        //获取最近的服务节点
        String node = consistentHash.getNode(path);
        for (ServiceInstance instance : serviceInstanceSet) {
            if (instance.getInstanceId().equals(node)) {
                return instance;
            }
        }

        //默认返回第一个实例
        return serviceInstanceSet.iterator().next();
    }

}

class ConsistentHash {
    //真实服务节点列表
    private static List<String> realNodes = new LinkedList<String>();
    //虚拟服务节点个数
    private static final int VIRTUAL_NUM = 20;
    // 虚拟服务节点分配，key是hash值，value是虚拟服务节点服务器名称
    private static SortedMap<Integer, String> shards = new TreeMap<Integer, String>();

    //构建一致性哈希环
    public ConsistentHash(List<String> nodes){
        for(String node : nodes){
            addNode(node);
        }
    };

     //FNV1_32_HASH算法
    public int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++)
            hash = (hash ^ str.charAt(i)) * p;
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        // 如果算出来的值为负数则取其绝对值
        if (hash < 0)
            hash = Math.abs(hash);
        return hash;
    }

    //添加哈希环节点
    public void addNode(String node){
        if(!realNodes.contains(node)) {
            //添加真实节点
            realNodes.contains(node);
            //添加虚拟节点
            for(int i=0;i<VIRTUAL_NUM;i++){
                String virtualNode = node + "&&VN" + i;
                int hash = this.getHash(virtualNode);
                shards.put(hash,virtualNode);
            }
        }
    }

    //获取被分配的服务节点(instandId)
    public String getNode(String node){
        //没有服务
        if(realNodes.isEmpty()) return null;

        int hash = getHash(node);
        Integer key = null;
        SortedMap<Integer,String> subMap = shards.tailMap(hash);
        if(subMap.isEmpty()){
            key = shards.lastKey();
        }else{
            key = subMap.firstKey();
        }
        String virtualNode = shards.get(key);
        return virtualNode.substring(0, virtualNode.indexOf("&&"));
    }
}
